home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / elvis-17.lha / elvis-1.7 / vmsio.c < prev    next >
C/C++ Source or Header  |  1993-01-06  |  19KB  |  675 lines

  1. /*
  2.    VMSIO.C -- replacements for lseek(), read() and close() to allow
  3.               arbitrary byte seeks with non-stream-lf files.
  4.              
  5.    (The original version (file routines) were written to port the
  6.     unix ``less'' program.  This version helps with the elvis port.
  7.     It may be useful elsewhere to port other utilities.)
  8.  
  9.    Written by John Campbell  CAMPBELL@NAUVAX.bitnet.   Use as you
  10.    wish, but leave me some credit for killing myself on this when
  11.    I was sick one weekend, ok?
  12.  
  13.    Also, added vms_rename as a weak replacment for link().  4/2/91
  14.    ...and because there was a routine named delete, created a vms_delete.
  15.  
  16.    Sigh, Steve wanted pipe stuff, so vms_rpipe(), vms_pread() and
  17.    vms_pclose() was born.                                   8/2/91
  18.  
  19.    Moved the tty i/o routines into this module as well.  vms_open_tty()
  20.    and vms_ttyread()  (ttread)                              8/2/91
  21. */
  22.  
  23. /*
  24. Entry points:
  25.  
  26. FILE I/O
  27. vms_close (fd)
  28. long vms_lseek (fd, offset, direction)
  29. int vms_read (fd, buf, len)
  30. int vms_rename (from, to)
  31. vms_delete (file)
  32.  
  33. PIPE I/O
  34. int vms_rpipe (cmd, fd, input_file)
  35. int vms_pread (pfile, buffer, size)
  36. int vms_rpclose(pfile)
  37.  
  38. TERMINAL I/O
  39. vms_open_tty()
  40. vms_ttyread(buf, len, time)
  41. */
  42. static char *version = "VMSIO, version 1.0";
  43.  
  44. #include <stdio.h>
  45. #include <errno.h>
  46. #include <perror.h>
  47. #define BUFSIZE 4096
  48.  
  49. /* Data and buffers used to implement vms_lseek() and vms_read() */
  50.    static struct {
  51.       int type, cur_loc, size, lastbin, maxbin, offset, eob;
  52.    } fdints[_NFILE] =
  53.       {{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},
  54.        {0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},
  55.        {0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},
  56.        {0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},
  57.        {0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1}};
  58.    static char **fdbufs[_NFILE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  59. typedef struct {
  60.         int loc, bstart, bend;
  61. } seeks;
  62.    static seeks *fdseeks[_NFILE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  63.  
  64. /* Intended use for fdseeks:  fdseeks[fd][i] for i'th triple */
  65.  
  66. #define G_cur_loc  fdints[fd].cur_loc
  67. #define G_size     fdints[fd].size
  68. #define G_eof_seen fdints[fd].eof_seen
  69. #define G_offset   fdints[fd].offset
  70. #define G_eob      fdints[fd].eob
  71.  
  72.  
  73. vms_close (fd)
  74. int fd;
  75. {
  76.    if (fd >= 0) {
  77.    /* Reset fdints[fd] and free any buffers we were using. */
  78.       fdints[fd].type    = 0;
  79.       fdints[fd].cur_loc = 0;
  80.       fdints[fd].size    = 0;
  81.       fdints[fd].lastbin = 0;
  82.       fdints[fd].maxbin  = 0;
  83.       fdints[fd].offset  = 0;
  84.       fdints[fd].eob     = -1;
  85.  
  86.       if (fdseeks[fd])
  87.          fdseeks[fd] = free (fdseeks[fd]);
  88.       if (fdbufs[fd])
  89.          fdbufs[fd]  = free (fdbufs[fd]);
  90.    }
  91.    return (close(fd));
  92. }
  93.  
  94. long vms_lseek (fd, offset, direction)
  95. int fd, offset, direction;
  96. {
  97.    int tmp;
  98.  
  99.    if (fd > _NFILE) {
  100.       fprintf (stderr,"Too many files for vms_lseek\n");
  101.       exit(2);
  102.    }
  103.    if (fd < 0) {
  104.       return lseek (fd, offset, direction);
  105.    }
  106.    if (fdints[fd].type == 0)
  107.       _init(fd);
  108.    if (fdints[fd].type == 1)
  109.       return lseek (fd, offset, direction);
  110.  
  111. /* Convert the possibly relative `offset' to an absolute offset. */
  112.    if (direction == 1) {
  113.       offset = G_cur_loc + offset + G_offset;
  114.    }
  115.    else if (direction == 2) {
  116.       if (G_eob == -1)
  117.          _refill (fd, -1);   /* Figure out the correct eob byte count */
  118.       offset = G_eob + offset;
  119.    }
  120.    if (offset < 0)
  121.       return -1;
  122.  
  123. /* Limitation of this implementation--only seeks to end of file. */
  124.    if (G_eob > -1 && offset > G_eob)
  125.       offset = G_eob;
  126.  
  127.    if (G_offset > offset || offset >= G_offset + G_size) {
  128.       if (_refill (fd, offset) == -1)
  129.          return -1;
  130.    }
  131.  
  132. /* Byte we want is now in our current buffer. */
  133.    G_cur_loc = offset - G_offset;
  134.  
  135. /* Sanity check. */
  136.    if (G_cur_loc < 0 || G_cur_loc > BUFSIZE)
  137.       _error ("G_cur_loc error in vms_lseek\n", 1);
  138.  
  139.    return G_cur_loc + G_offset;   /* Byte location in current buffer */
  140. }
  141.  
  142.  
  143. int vms_read (fd, buf, len)
  144. int fd, len;
  145. char *buf;
  146. {
  147. /* Buffer the read as the unix system would do. */
  148.    int  fill = 0, n, num = 0,tmp;
  149.    char *buffer;
  150.  
  151.    if (fd > _NFILE) {
  152.       fprintf (stderr,"Too many files for vms_read\n");
  153.       exit(2);
  154.    }
  155.  
  156.    if (fdints[fd].type == 0)
  157.       _init(fd);
  158.    if (fdints[fd].type == 1)
  159.       return read (fd, buf, len);
  160.  
  161.    buffer = fdbufs[fd];
  162.  
  163.    if (G_eob != -1 && G_cur_loc + G_offset >= G_eob)
  164.       return 0;   /* EOF */
  165.  
  166. /* Move any buffered data into place. */
  167.    while (len && G_cur_loc < G_size)  {
  168.       *buf++ = buffer[G_cur_loc++];
  169.       --len;
  170.       ++num;
  171.    }
  172. /* Refill as many buffers as necessary to put len bytes into buf. */
  173.    do {
  174.    /* Don't refill when asked to read beyond the end of the file. */
  175.       if (G_cur_loc == G_size && (G_eob == -1 || G_offset + G_size < G_eob)) {
  176.          if (_refill (fd, G_offset + G_size) == -1) return -1;
  177.       }
  178.       while (len && G_cur_loc < G_size)  {
  179.          *buf++ = buffer[G_cur_loc++];
  180.          --len;
  181.          ++num;
  182.       }
  183.    } while (len && (G_eob == -1 || G_offset + G_size < G_eob));
  184. /* Sanity check. */
  185.    if (G_cur_loc < 0 || G_cur_loc > BUFSIZE)
  186.       _error ("G_cur_loc bad in vms_read", 1);
  187.  
  188.    return num;
  189. }
  190.  
  191. /*
  192.    Fill from the appropriate buffer.  Note that offset is a true byte
  193.    offset and needs to be converted to fdseeks[fd][i].loc before seeking.
  194.    This technique may, in fact, generalize to other machines.
  195. */
  196. static int _refill (fd, offset)
  197. int fd, offset;
  198. {
  199.    int n, seekbin, tmp;
  200.    char *buffer = fdbufs[fd];
  201.  
  202. /* See if the offset is in our current buffer (eob offset is a pain). */
  203.    if (offset > 0 && G_eob > -1 && offset >= G_eob)
  204.       offset = G_eob - 1;
  205.  
  206.    if (offset > 0 && G_offset <= offset && offset < G_offset + G_size)
  207.       return G_offset;
  208.  
  209.    seekbin = fdints[fd].lastbin;
  210.  
  211. /* Now see if the offset is known (already been read once). */
  212.    if (offset >= 0 && offset < fdseeks[fd][seekbin].bstart) {
  213.    /* Yes!  We can seek to a known point to pick up this offset. */
  214.       while (seekbin > 0) {
  215.          if (offset >= fdseeks[fd][seekbin].bstart)
  216.            break;
  217.          --seekbin;
  218.       }
  219.    }
  220. /* Position ourselves for the read (even if we are already there?) */
  221. /* We can avoid this lseek if G_offset == [seekbin-1].bstart */
  222.    if (lseek (fd, fdseeks[fd][seekbin].loc, 0) == -1)
  223.       _error ("bad seek in _refill");
  224.  
  225. /* Ok, fill this buffer. */
  226. more:
  227.    G_cur_loc = 0;
  228.    G_size = 0;
  229.    G_offset = fdseeks[fd][seekbin].bstart;
  230.  
  231. /*
  232.    Don't want to be left with a partial record.  Choices are to shrink
  233.    down the read size or to keep seeking so we can backup to just before
  234.    n == read size.  Which seems faster?  Which puts an arbitrary limit
  235.    on the record size?
  236. */
  237.    /* Some lines longer than 512 may be truncated. */
  238.       while (G_size < BUFSIZE - 512 &&
  239.                 (n = read (fd, &buffer[G_size], BUFSIZE - G_size)) > 0) {
  240. #ifdef OTHERMETHOD
  241.          if (n == BUFSIZE - G_size)
  242.             break;   /* Don't count last line (it may be a partial line) */
  243. #endif
  244.          G_size += n;
  245.       }
  246.       if (n == 0) {
  247.          if (G_size == 0)
  248.             ++G_size;
  249.          G_eob = G_offset + G_size;
  250.          offset = G_eob;
  251.       }
  252.       else if (n == -1) {
  253.          _error ("vms_read (_refill) error", 0);
  254.          return -1;
  255.       }
  256.  
  257. /* Update the seek array.  Finish current bin and start next bin. */
  258.    if (G_size == 0)
  259.       ++G_size;
  260.    tmp = G_offset + G_size - 1;
  261.    if (seekbin < fdints[fd].lastbin && fdseeks[fd][seekbin].bend != tmp) {
  262.       fprintf (stderr, "Consistency failure in _refill\n");
  263.       exit(2);
  264.    }
  265.    fdseeks[fd][seekbin].bend = tmp;
  266.    if (G_eob == -1 || G_offset + G_size < G_eob) {
  267.    /* Set up the next seek bin */
  268.       if (++seekbin > fdints[fd].maxbin) {
  269.       /* Make more room. */
  270.          fdints[fd].maxbin = 2*fdints[fd].maxbin;
  271.          fdseeks[fd] = (void *)realloc (fdseeks[fd], fdints[fd].maxbin);
  272.       }
  273.  
  274.    /* Make sure that lastbin is up to date. */
  275.       if (seekbin > fdints[fd].lastbin) fdints[fd].lastbin = seekbin;
  276.  
  277.       if ((tmp = lseek(fd,0,1)) == -1)
  278.          _error ("Seek error in vms_read (refill)");
  279.       if (seekbin < fdints[fd].lastbin && fdseeks[fd][seekbin].loc != tmp) {
  280.          fprintf (stderr, "Consistency failure in _refill\n");
  281.          exit(2);
  282.       }
  283.       fdseeks[fd][seekbin].loc = tmp;
  284.  
  285.       if (seekbin >= fdints[fd].lastbin) {
  286.          fdseeks[fd][seekbin].bstart = G_offset + G_size;
  287.          fdseeks[fd][seekbin].bend = 0;
  288.       }
  289.       else {
  290.       /* Consistency check */
  291.          tmp = G_offset + G_size;
  292.          if (fdseeks[fd][seekbin].bstart != tmp) {
  293.             fprintf (stderr, "Consistency failure in _refill\n");
  294.             exit(1);
  295.          }
  296.       }
  297.    }
  298. /* Well, it's either a big do-while loop or this goto... */
  299.    if (offset == -1 ||
  300.      (offset >= G_offset + G_size && (offset < G_eob || G_eob == -1)))
  301.       goto more;
  302.  
  303.    return G_offset;
  304. }
  305.  
  306. #include <types.h>
  307. #include <stat.h>
  308. /*
  309.    Note: may want to store a pointer to the statbuf in place of type.
  310.    For one thing, this would give you the maximum record size.
  311.  
  312.    Ok, there are some problems when we don't control open and close.
  313.    For instance, switching fd's in midstream can throw us.  We could
  314.    store a statbuf pointer to detect this and it may turn out to be
  315.    necessary later.  (statbuf has the fid for the file in it.)
  316. */
  317. static _init(fd)
  318. int fd;
  319. {
  320. /* Check the file type; allocate a buffer. */
  321.    struct stat statbuf;
  322.    int tmp;
  323.  
  324.    if (fstat(fd, &statbuf) < 0)
  325.       _error ("Can't stat\n", 1);
  326. /*
  327.    Some possible file types (from fab.h):
  328.  
  329.    rat: FTN - 0      rfm: UDF   0  undefined
  330.         CR  - 1           FIX   1
  331.         PRN - 2           VAR   2  default type
  332.         BLK - 3           VFC   3
  333.                           STM   4
  334.                           STMLF 5
  335.                           STMCR 6
  336. Also, st_size == 0 seems to indicate a non-file device (mailbox, terminal).
  337. */
  338.    if (statbuf.st_fab_rfm == 5 || statbuf.st_fab_rfm == 0
  339.                                         || statbuf.st_size == 0)
  340.       fdints[fd].type = 1;  /* Use 'C' rtl routines directly */
  341.    else
  342.       fdints[fd].type = 2;  /* Use these routines. */
  343.  
  344. /* Get a buffer for our buffered I/O */
  345.    fdbufs[fd] = malloc (BUFSIZE);
  346.  
  347. /* Get an array to use for seeking (initial guess). */
  348.    tmp = (statbuf.st_size + BUFSIZE)/BUFSIZE * sizeof(seeks) + sizeof(seeks);
  349.    fdseeks[fd] = (void *)malloc (tmp);
  350.    fdints[fd].maxbin = tmp/sizeof(seeks);
  351.  
  352. /* Fill in the 0'th (first) seeks triplet. */
  353.    fdseeks[fd][0].loc    = 0;
  354.    fdseeks[fd][0].bstart = 0;
  355.    fdseeks[fd][0].bend   = 0;
  356. }
  357.  
  358. #include <descrip.h>
  359. static _error (string, leave)
  360. char *string;
  361. int leave;
  362. {
  363.    char errstr[81];
  364.    $DESCRIPTOR(errdesc,errstr);
  365.    short int length;
  366.  
  367.    perror (string);
  368.    if (errno == EVMSERR) {
  369.       if (SYS$GETMSG(vaxc$errno, &length, &errdesc, 1, 0) == 1) {
  370.           errstr[length] = '\0';
  371.           fprintf (stderr, "%s\n", errstr);
  372.       }
  373.    }
  374.    if (leave)
  375.       exit (44);  /* SS_ABORT */
  376. }
  377. #include <ssdef>
  378. #include <iodef>
  379. #include <rms>
  380. #include <fibdef>
  381. #include <atrdef>
  382.  
  383. /* Simply need a trick to hide a global called 'delete' elsewhere. */
  384. vms_delete (file)
  385. char *file;
  386. {
  387.    delete (file);
  388. }
  389.  
  390. /* Pipe routines modified from Chris Janton's (chj) VMS Icon port. */
  391. /*
  392.    Here we fudge to help the "elvis" program implement rpipe.  The
  393.    routine essentially does an popen using fd as stdin--except that
  394.    few VMS utilities use the 'C' library.  So we pass in the standard
  395.    input file name and use it if fd is non-zero.
  396. */
  397. #include <dvidef>
  398. #include <file>
  399.  
  400. typedef struct _descr {
  401.    int length;
  402.    char *ptr;
  403. } descriptor;
  404.  
  405. typedef struct _pipe {
  406.    long pid;                    /* process id of child */
  407.    long status;                 /* exit status of child */
  408.    long flags;                  /* LIB$SPAWN flags */
  409.    int ichan;                 /* MBX channel number */
  410.    int ochan;
  411.    int efn;
  412.    unsigned running : 1;        /* 1 if child is running */
  413. } Pipe;
  414.  
  415. Pipe _pipes[_NFILE];            /* one for every open file */
  416.  
  417. #define NOWAIT          1
  418. #define NOCLISYM        2
  419. #define NOLOGNAM        4
  420. #define NOKEYPAD        8
  421. #define NOTIFY          16
  422. #define NOCONTROL       32
  423. #define SFLAGS  (NOWAIT|NOKEYPAD|NOCONTROL)
  424.  
  425. int vms_rpipe (cmd, fd, input_file)
  426. char *cmd, *input_file;
  427. int fd;
  428. {
  429.    int pfile;                   /* the Pfile */
  430.    Pipe *pd;                    /* _pipe database */
  431.    descriptor inmbxname;        /* name of input mailbox */
  432.    descriptor outmbxname;          /* name of mailbox */
  433.    char inmname[65];
  434.    char outmname[65];              /* mailbox name string */
  435.    int ochan;                    /* mailbox channel number */
  436.    int ichan;                  /* Input mailbox channel number */
  437.    int status;                  /* system service status */
  438.    int efn;
  439.    struct {
  440.       short len;
  441.       short code;
  442.       char *address;
  443.       char *retlen;
  444.       int last;
  445.    } itmlst;
  446.  
  447.    if (!cmd || cmd[0] == '\0')
  448.       return (-1);
  449.    LIB$GET_EF(&efn);
  450.    if (efn == -1)
  451.       return (-1);
  452.  
  453.    /* create and open the input mailbox */
  454.    status = SYS$CREMBX(0, &ichan, 0, 0, 0, 0, 0);
  455.    if (!(status & 1)) {
  456.       LIB$FREE_EF(&efn);
  457.       return (-1);
  458.    }
  459.    itmlst.last = inmbxname.length = 0;
  460.    itmlst.address = inmbxname.ptr = inmname;
  461.    itmlst.retlen = &inmbxname.length;
  462.    itmlst.code = DVI$_DEVNAM;
  463.    itmlst.len = 64;
  464.    status = SYS$GETDVIW(0, ichan, 0, &itmlst, 0, 0, 0, 0);
  465.    if (!(status & 1)) {
  466.       LIB$FREE_EF(&efn);
  467.       return (-1);
  468.    }
  469.    inmname[inmbxname.length] = '\0';
  470.  
  471.    /* create and open the output mailbox */
  472.    status = SYS$CREMBX(0, &ochan, 0, 0, 0, 0, 0);
  473.    if (!(status & 1)) {
  474.       LIB$FREE_EF(&efn);
  475.       return (-1);
  476.    }
  477.    itmlst.last = outmbxname.length = 0;
  478.    itmlst.address = outmbxname.ptr = outmname;
  479.    itmlst.retlen = &outmbxname.length;
  480.    status = SYS$GETDVIW(0, ochan, 0, &itmlst, 0, 0, 0, 0);
  481.    if (!(status & 1)) {
  482.       LIB$FREE_EF(&efn);
  483.       return (-1);
  484.    }
  485.    outmname[outmbxname.length] = '\0';
  486.    pfile = open(outmname, O_RDONLY);
  487.    if (pfile < 0) {
  488.       LIB$FREE_EF(&efn);
  489.       SYS$DASSGN(ichan);
  490.       SYS$DASSGN(ochan);
  491.       return (-1);
  492.    }
  493.    /* Save file information now */
  494.    pd = &_pipes[pfile]; /* get Pipe pointer */
  495.    pd->pid = pd->status = pd->running = 0;
  496.    pd->flags = SFLAGS;
  497.    pd->ichan = ichan;
  498.    pd->ochan = ochan;
  499.    pd->efn = efn;
  500.  
  501.    /* Initiate the command by writing down the input mailbox (SYS$INPUT). */
  502.    if (fd > 0) {
  503.       char *pre_command[132+12];
  504.       strcpy (pre_command, "DEFINE/USER SYS$INPUT ");
  505.       strcat (pre_command, input_file);
  506.       status = sys$qiow(0, ichan, IO$_WRITEVBLK | IO$M_NOW, 0, 0, 0,
  507.                         pre_command, strlen(pre_command), 0, 0, 0, 0);
  508.       if (!(status & 1)) {
  509.          LIB$FREE_EF(&efn);
  510.          SYS$DASSGN(ichan);
  511.          SYS$DASSGN(ochan);
  512.          return (-1);
  513.       }
  514.    }
  515.    status = sys$qiow(0, ichan, IO$_WRITEVBLK | IO$M_NOW,
  516.                                 0, 0, 0, cmd, strlen(cmd), 0, 0, 0, 0);
  517.    if (!(status & 1)) {
  518.       LIB$FREE_EF(&efn);
  519.       SYS$DASSGN(ichan);
  520.       SYS$DASSGN(ochan);
  521.       return (-1);
  522.    }
  523.    status = sys$qiow(0, ichan, IO$_WRITEOF | IO$M_NOW, 0, 0, 0,
  524.                                                           0, 0, 0, 0, 0, 0);
  525.    if (!(status & 1)) {
  526.       LIB$FREE_EF(&efn);
  527.       SYS$DASSGN(ichan);
  528.       SYS$DASSGN(ochan);
  529.       return (-1);
  530.    }
  531.  
  532.    status = LIB$SPAWN(0,
  533.       &inmbxname,                          /* input file */
  534.       &outmbxname,                         /* output file */
  535.       &pd->flags, 0, &pd->pid, &pd->status, &pd->efn, 0, 0, 0, 0);
  536.    if (!(status & 1)) {
  537.       LIB$FREE_EF(&efn);
  538.       SYS$DASSGN(ichan);
  539.       SYS$DASSGN(ochan);
  540.       return (-1);
  541.    } else {
  542.       pd->running = 1;
  543.    }
  544.    return (pfile);
  545. }
  546.  
  547. int vms_pread (pfile, buffer, size)
  548. int pfile, size;
  549. char *buffer;
  550. /* Be compatible when we read data in (handle newlines). */
  551. {
  552.    Pipe *pd;
  553.    int status, request;
  554.    struct {
  555.       short  status,
  556.              count;
  557.       int       :16;
  558.    } iosb;
  559.  
  560.    pd = pfile >= 0 ? &_pipes[pfile] : 0;
  561.    if (pd == NULL) return -1;
  562.  
  563. /*
  564.    This is sort of nasty.  The default mailbox size is 256 maxmsg
  565.    and 1056 bufquo if your sysgen parameters are standard.  Asking
  566.    for more on the CREMBX command (in rpipe) might be a bad idea as
  567.    that could cause an "exceeded quota" error.  Since we only return
  568.    -1 on error, there's no hope that the poor user would ever know
  569.    what went wrong.
  570. */
  571.    request = size > 256 ? 256 : size - 1;
  572.    status = sys$qiow(0, pd->ochan, IO$_READVBLK, &iosb, 0, 0,
  573.                                       buffer, request, 0, 0, 0, 0);
  574.    if (!(status & 1)) return -1;
  575.    if (iosb.status == SS$_ENDOFFILE)
  576.       return 0;
  577.    buffer[iosb.count] = '\n';
  578.    return iosb.count+1;
  579. }
  580.  
  581. /*
  582.  * Taken from pclose - close a pipe
  583.  * Last modified 2-Apr-86/chj
  584.  *
  585.  */
  586. int vms_rpclose(pfile)
  587. int pfile;
  588. {
  589.    Pipe *pd;
  590.    int status;
  591.    int fstatus;
  592.  
  593.    pd = pfile >= 0 ? &_pipes[pfile] : 0;
  594.    if (pd == NULL)
  595.       return (-1);
  596.    fstatus = close(pfile);
  597.    SYS$DASSGN(pd->ichan);
  598.    SYS$DASSGN(pd->ochan);
  599.    LIB$FREE_EF(&pd->efn);
  600.    pd->running = 0;
  601.    return (fstatus);
  602. }
  603.  
  604. /* Terminal routines. */
  605.  
  606. static int tty;
  607. static int VMS_term_chan;
  608. int VMS_read_raw;   /* Set by curses.c in elvis. */
  609.  
  610. #define VMSCheck(a) {int _s; if (~(_s = (a)) & 1) vms_sys$exit (_s);}
  611.  
  612. vms_open_tty()
  613. {
  614.    int c;
  615.  
  616.    $DESCRIPTOR(_terminal,"SYS$INPUT");
  617.    if (VMS_term_chan == 0) {
  618.       VMSCheck(SYS$ASSIGN (&_terminal, &VMS_term_chan, 0, 0));
  619.    }
  620. /* Was 2 -- jdc */
  621.    tty = 0;
  622.  
  623. /* Could reset the scrolling region, setup LINES, COLS, etc. */
  624.  
  625.    read(tty,&c,0);   /* Flush the tty buffer. */
  626. }
  627.  
  628. /*
  629.  * Get a character from the keyboard.
  630.  */
  631. /*ARGSUSED*/
  632. vms_ttyread(buf, len, time)
  633.         char *buf;
  634.         int len;
  635.         int time;
  636. {
  637.         char c;
  638.         int result, terminat[2] = {0,0};
  639.    struct {
  640.       short int status;              /* I/O completion status */
  641.       short int bcount;              /* byte transfer count   */
  642.       int dev_dep_data;              /* device dependant data */
  643.    } iosb;                  /* This is a QIO I/O Status Block */
  644.  
  645.  
  646.    if (VMS_read_raw) {
  647. /*      read(tty,&c,0);  */ /* Flush the tty buffer. (needed?) */
  648.       if (time == 0) {
  649.          VMSCheck(sys$qiow(0, VMS_term_chan,
  650.            IO$_READVBLK | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TRMNOECHO,
  651.                  &iosb, 0, 0, buf, 1, 0, terminat, 0, 0));
  652.       }
  653.       else {
  654.          VMSCheck(sys$qiow(0, VMS_term_chan,
  655.         IO$_READVBLK | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TRMNOECHO | IO$M_TIMED,
  656.                  &iosb, 0, 0, buf, 1, time, terminat, 0, 0));
  657.       }
  658.       if (iosb.status == SS$_ENDOFFILE)
  659.          vms_sys$exit(SS$_ABORT);
  660.       else if (iosb.status == SS$_TIMEOUT)
  661.          return 0; /* Timeout */
  662.       return 1;  /* iosb.bcount; */
  663.    }
  664.    else {
  665. /* I don't believe we ever use ttyread to read in non-raw mode... */
  666. #undef read
  667.       return read (0, buf, len);
  668.    }
  669. }
  670.  
  671. vms_sys$exit(val)
  672. {
  673.    sys$exit(val);   /* Debugger entry point. */
  674. }
  675.